package com.cuit.remoting.transport.netty.server;

import com.cuit.factory.SingleFactory;
import com.cuit.remoting.transport.netty.client.ChannelProvider;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;

import java.net.SocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@ChannelHandler.Sharable
public class IdleStateTrigger extends ChannelDuplexHandler {
    private static final int MAX_LOSS_BEAT_COUNT = 2;
    private final ChannelProvider channelProvider;
    private final Map<String, AtomicInteger> lossBeatCounts;

    public IdleStateTrigger() {

        this.lossBeatCounts = new ConcurrentHashMap<>();
        this.channelProvider = SingleFactory.getSingle(ChannelProvider.class);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        //需要统计超过两次心跳才会关闭,也就是第三次
        SocketAddress socketAddress = ctx.channel().remoteAddress();
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                log.info("服务器没有收到[{}]的心跳信息", socketAddress.toString());
                AtomicInteger lossCountBeat = lossBeatCounts.getOrDefault(socketAddress.toString(), new AtomicInteger(0));
                lossBeatCounts.put(socketAddress.toString(), lossCountBeat);
                int count = lossCountBeat.incrementAndGet();
                if (count >= MAX_LOSS_BEAT_COUNT){
                    log.info("超过最大丢失心跳包数，关闭客户端[{}]连接", socketAddress.toString());
                    ctx.channel().close();
                }
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
